#include "Graphics.h"
#include "FileSystem.h"

Graphics* Graphics::graphics;

namespace Uniforms
{
	//progame
	GLuint program;     
	GLuint programCube;   

	//3d
    GLint uWvpMatrix;
	GLint uSampler;	
   
	//cube
	GLint uCubeMVPMatrix;   
	GLint uCubeSampler;
};

Graphics::Graphics()
{  
	graphics = NULL;
}

Graphics::~Graphics()
{    
}

Graphics* Graphics::GetGraphics()
{
	if ( graphics == NULL )
		graphics = new Graphics();
	return graphics;
}

// Init the graphics.
void Graphics::InitGraphics()
{
    Uniforms::program = LoadProgram("vShader.vsh","fShader.fsh");  	
    Uniforms::uWvpMatrix = glGetUniformLocation(Uniforms::program, "uWvpMatrix");    
    Uniforms::uSampler = glGetUniformLocation(Uniforms::program, "uSampler");
}

void Graphics::LoadShader()
{
	//cube
	Uniforms::programCube = LoadProgram("vShaderCube.vsh","fShaderCube.fsh"); 
	Uniforms::uCubeMVPMatrix = glGetUniformLocation(Uniforms::programCube, "uCubeMVPMatrix");		
	Uniforms::uCubeSampler = glGetUniformLocation(Uniforms::programCube, "uCubeSampler");
}

// Compile a Shader
GLuint Graphics::CompileShader(const char *source, int type)
{
    GLint status = 0;
    GLuint shader = glCreateShader(type);
    glShaderSource(shader, 1, &source, NULL);
    glCompileShader(shader);
    glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
    
    if (status == GL_FALSE)
    {
        LOGE("Error When Compiling Source: \n%s\n", source);
        shader = 0; // clear the shader
    }    
    return shader;
}

//Load program
GLuint Graphics::LoadProgram(char fileVShader[], char fileFShader[])
{
	GLint status = 0;
    FileSystem *fileSystem = FileSystem::GetFileSystem();
    char *vertexShaderSource = fileSystem->GetContent(fileVShader);
    char *fragmentShaderSource = fileSystem->GetContent(fileFShader);
    GLuint vertexShader = 0, fragmentShader = 0, program = 0;
    vertexShader = CompileShader(vertexShaderSource, GL_VERTEX_SHADER);
    fragmentShader = CompileShader(fragmentShaderSource, GL_FRAGMENT_SHADER);
    
    if (!(vertexShader && fragmentShader))
    {
        return ERROR_COMPILE_SHADER;
    }
    
    program = glCreateProgram();
    
    glAttachShader(program, vertexShader);
    glAttachShader(program, fragmentShader);
    
    glBindAttribLocation(program, ATTRIB_POSITION, "aPosition");
	glBindAttribLocation(program, ATTRIB_TEXCOORD, "aTexCood");
    glLinkProgram(program);
    glGetProgramiv(program, GL_LINK_STATUS, &status);    
    
    if (status == GL_FALSE)
    {
        LOGE("Couldn't Link Shaders: Error #%d\n", glGetError());
        return ERROR_LINK_SHADER;
    }

	return program;
}

void Graphics::SetProgram ( int program )
{
	glUseProgram ( program );
}